/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package batailledesardennes.util.geomFloat;

import batailledesardennes.util.FastMath;

/**
 *
 * @author charly
 */
public class Point extends Shape {

    private float x;
    private float y;

    public Point() {
    }

    public Point(float x, float y) {
        this.x = x;
        this.y = y;
    }

    public Point(Point p) {
        x = p.x;
        y = p.y;
    }

    public float getX() {
        return x;
    }

    public void setX(float x) {
        this.x = x;
    }

    public float getY() {
        return y;
    }

    public void setY(float y) {
        this.y = y;
    }

    public void setPos(float x, float y) {
        this.x = x;
        this.y = y;
    }

    public void setPos(Point p) {
        this.x = p.x;
        this.y = p.y;
    }

    @Override
    public Point translate(float x, float y) {
        this.x += x;
        this.y += y;
        return this;
    }

    @Override
    public Point rotate(float angle, float centerX, float centerY) {
        if (centerX == x && centerY == y) {
            return this;
        }
        float totAngle = angle + FastMath.atan2(y - centerY, x - centerX);
        float dist = distance(centerX, centerY);
        x = centerX + dist * FastMath.cos(totAngle);
        y = centerY + dist * FastMath.sin(totAngle);
        return this;
    }

    public boolean posEquals(Point p) {
        return p.x == x && p.y == y;
    }

    public boolean posEquals(float x, float y) {
        return this.x == x && this.y == y;
    }

    public float distance(Point p) {
        return GeomUtils.distance(x, y, p.x, p.y);
    }

    public float distance(float x, float y) {
        return GeomUtils.distance(this.x, this.y, x, y);
    }

    public float distanceSq(Point p) {
        return GeomUtils.distanceSq(x, y, p.x, p.y);
    }

    public float distanceSq(float x, float y) {
        return GeomUtils.distanceSq(this.x, this.y, x, y);
    }

    public boolean colinear(Point p1, Point p2) {
        return GeomUtils.collinear(x, y, p1.x, p1.y, p2.x, p2.y);
    }

    public boolean colinear(float x1, float y1, float x2, float y2) {
        return GeomUtils.collinear(x, y, x1, y1, x2, y2);
    }

    public int ccw(Point p) {
        return GeomUtils.ccw(x, y, p.x, p.y);
    }

    public int ccw(float x, float y) {
        return GeomUtils.ccw(this.x, this.y, x, y);
    }
    

    public float findSignedAngle(Point p) {
        return GeomUtils.findSignedAngle(x, y, p.x, p.y);
    }

    public float findSignedAngle(float x, float y) {
        return GeomUtils.findSignedAngle(this.x, this.y, x, y);
    }

    public float findSignedAngleRelative(Point p, Point relPoint) {
        return GeomUtils.findSignedAngleRelative(relPoint.x, relPoint.y, x, y, p.x, p.y);
    }

    public float findAngle(Point p) {
        return GeomUtils.findAngle(x, y, p.x, p.y);
    }

    public float findAngle(float x, float y) {
        return GeomUtils.findAngle(this.x, this.y, x, y);
    }

    public float findAngleRelative(Point p, Point relPoint) {
        return GeomUtils.findAngleRelative(relPoint.x, relPoint.y, x, y, p.x, p.y);
    }

    public Point midPoint(Point p) {
        return GeomUtils.midPoint(x, y, p.x, p.y);
    }

    public Point midPoint(float x, float y) {
        return GeomUtils.midPoint(this.x, this.y, x, y);
    }

    public Point pointInDirection(float angle, float dist) {
        return GeomUtils.pointInDirection(x, y, angle, dist);
    }

    public float distToLineSq(Point p1, Point p2) {
        return GeomUtils.distToLineSq(x, y, p1.x, p1.y, p2.x, p2.y);
    }

    public float distToLineSq(float x1, float y1, float x2, float y2) {
        return GeomUtils.distToLineSq(x, y, x1, y1, x2, y2);
    }

    public float distToLine(Point p1, Point p2) {
        return GeomUtils.distToLine(x, y, p1.x, p1.y, p2.x, p2.y);
    }

    public float distToLine(float x1, float y1, float x2, float y2) {
        return GeomUtils.distToLine(x, y, x1, y1, x2, y2);
    }

    public float distToSegSq(Point p1, Point p2) {
        return GeomUtils.distToSegSq(x, y, p1.x, p1.y, p2.x, p2.y);
    }

    public float distToSegSq(float x1, float y1, float x2, float y2) {
        return GeomUtils.distToSegSq(x, y, x1, y1, x2, y2);
    }

    public float distToSeg(Point p1, Point p2) {
        return GeomUtils.distToSeg(x, y, p1.x, p1.y, p2.x, p2.y);
    }

    public float distToSeg(float x1, float y1, float x2, float y2) {
        return GeomUtils.distToSeg(x, y, x1, y1, x2, y2);
    }

    public Point getClosestPointOnSegment(Point p1, Point p2) {
        return GeomUtils.getClosestPointOnSegment(x, y, p1.x, p1.y, p2.x, p2.y);
    }

    public Point getClosestPointOnSegment(float x1, float y1, float x2, float y2) {
        return GeomUtils.getClosestPointOnSegment(x, y, x1, y1, x2, y2);
    }

    public Point getCopy() {
        return new Point(x, y);
    }

    @Override
    public boolean containsPoint(float x, float y) {
        return posEquals(x, y);
    }

    @Override
    public float getArea() {
        return 0;
    }

    @Override
    public float[] getBounds(float[] bounds) {
        if (bounds == null || bounds.length < 4) {
            bounds = new float[4];
        }
        bounds[0] = x;
        bounds[1] = y;
        bounds[2] = x;
        bounds[3] = y;
        return bounds;
    }

    @Override
    public Point getCenter() {
        return getCopy();
    }

    @Override
    public Point getClosestIntersectionWithLine(float x0, float y0, float x1, float y1) {
        if (colinear(x0, y0, x1, y1)) {
            return getCopy();
        }
        return null;
    }

    @Override
    public Point getClosestPoint(float x, float y, float dist) {
        Point p = getCopy();
        if (dist > 0) {
            float angle = findAngle(x, y);
            p.translate(dist * FastMath.cos(angle), dist * FastMath.sin(angle));
        }
        return p;
    }

    @Override
    public Point getBoundPointFromCenterTowards(float x, float y) {
        return getCopy();
    }

    @Override
    public float getPerimeter() {
        return 0;
    }

    @Override
    public float getRadius() {
        return 0;
    }

    @Override
    public boolean mayInteresectWith(Shape other) {
        if (other.getBoundsRect().containsPoint(this)) {
            return true;
        }
        return false;
    }

    @Override
    public boolean mayIntersectWithLine(float x0, float y0, float x1, float y1) {
        return colinear(x0, y0, x1, y1);
    }

    @Override
    public boolean intersects(Shape other) {
        return other.containsPoint(this);
    }

    @Override
    public boolean intersectsWithLineSegment(float x0, float y0, float x1, float y1) {
        return colinear(x0, y0, x1, y1);
    }

    @Override
    public Point scale(float sx, float sy, float x, float y) {
        if (sx == 1 && sy == 1 && x == this.x && y == this.y) {
            return this;
        }
        float distX = this.x - x;
        float distY = this.y - y;
        distX *= sx;
        distY *= sy;
        setX(x + distX);
        setY(y + distY);
        return this;
    }

    @Override
    public Point translateTo(float x, float y) {
        return translate(x - this.x, y - this.y);
    }

    @Override
    public boolean containsRect(float x, float y, float width, float height) {
        if (x == this.x && y == this.y && width == 0 && height == 0) {
            return true;
        }
        return false;
    }

    @Override
    public boolean intersectsRect(float x, float y, float width, float height) {
        if (x == this.x || x + width == this.x) {
            return y <= this.y && this.y <= height;
        }
        if (this.y == y || this.y == y + height) {
            return x <= this.x && this.x <= width;
        }
        return false;
    }
}
